/** Part of Zombie Navigator
	Copyright © 2016  Zombie Navigator Developers
	
	@file
	@module
	@license AGPL-3.0+
	
*/ 'use strict';


/* Used modules */
const _pEnv = require('./env');
const _pUri = require('./uri');
const _pMeta = require('./meta');
const _pTimer = require('./timer');
const _pZombieWindows = require('./zombie-windows');

/**
	Zombie scripts are only allowed to access variables starting with this
	string (*in addition* to the addon's prefix) thus resulting in:
	[addon's prefix] [this prefix] [script-controlled string]
	@private
*/
const ENV_PREFIX = 'DATA_';


/* Internal APIs */
const createSession = (scriptURI, policies) => {
	const pEnv = _pEnv, pUri = _pUri, pMeta = _pMeta, pTimer = _pTimer;
	const pZombieWindows = _pZombieWindows;
	const sessionEnv = Object.create(null);
	let sessionIsClosed = false;
	
	scriptURI = pUri.create(scriptURI);
	const isFromAddon = scriptURI.isPrivileged;
	if (!scriptURI.isQualified) {
		throw new TypeError('Invalid URI');
	}
	if (true === scriptURI.isRemote) {
		throw new TypeError('Remote script');
	}
	
	let sessionOpenHandlersQueue = []; // XXX: mutable
	const controlGroup = pZombieWindows.createControlGroup(scriptURI, policies);
	if (!(policies.openPrivate || policies.openNonPrivate)) {
		if (policies.openInvisible) {
			// open invisible pages...?
			throw new Error('Unimplemented: invisible pages');
		}
		throw new Error('Permission denied');
	} else {
		(policies.openPrivate
			? controlGroup.openPrivate() : controlGroup.openNonPrivate())
		.then(w => {
			controlGroup.showMessage('init', {__proto__: null
				,scriptURI: '' + scriptURI
				,policies: JSON.parse(JSON.stringify(policies))
				,system: '' + pMeta.getSystemDescription()
				,platform: '' + pMeta.getPlatformName()
				,platformVersion: '' + pMeta.getPlatformVersion()
				,product: '' + pMeta.getProductName()
				,productVersion: '' + pMeta.getProductVersion()
			});
			
			sessionOpenHandlersQueue.forEach(f => f());
			sessionOpenHandlersQueue = false;
		});
	}
	
	return Object.freeze({
		__proto__: null
		,onSessionStart (f) {
			if (sessionOpenHandlersQueue) { // pending
				sessionOpenHandlersQueue.push(f);
			} else {
				pTimer.setTimeout(() => void(f()));
			}
		}
		,onQuit (f) {
			controlGroup.onQuit(f);
		}
		,closeAll () {
			sessionIsClosed = true;
			controlGroup.closeAll();
		}
		,setEnv (name, value) {
			if (!name) throw new TypeError('Invalid variable name');
			sessionEnv[name + ''] = value ? value + '' : '';
		}
		,unsetEnv (name) {
			if (!name) throw new TypeError('Invalid variable name');
			sessionEnv[name + ''] = '';
		}
		,getEnv (name, value) {
			if (!name) throw new TypeError('Invalid variable name');
			name = name + '';
			if (name in sessionEnv) return sessionEnv[name] + '';
			
			const aName = ENV_PREFIX + name;
			if (!pEnv.has(aName)) return '';
			return pEnv.get(aName);
		}
		,getEnvName (name) {
			if (!name) throw new TypeError('Invalid variable name');
			const aName = ENV_PREFIX + name;
			return pEnv.toEnvName(aName);
		}
		,policies: policies
		,isFromAddon: !!isFromAddon
		,get isClosed () {
			return !!sessionIsClosed;
		}
		,openPrivateWindow () {
			if (!policies.openPrivate) {
				throw new Error('Not allowed by the policy');
			}
			return controlGroup.openPrivate();
		}
		,openWindow () {
			if (!policies.openNonPrivate) {
				return controlGroup.openPrivate();
			}
			return controlGroup.openNonPrivate();
		}
	});
};

/* Exports */
exports.createSession = createSession;

// vim: ts=4 noet ai

